package com.youlai.boot.modules.content.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.modules.content.model.entity.LzArticleTag;
import com.youlai.boot.modules.content.model.entity.LzCategory;
import com.youlai.boot.modules.content.model.entity.LzTag;
import com.youlai.boot.modules.content.service.LzArticleTagService;
import com.youlai.boot.modules.content.service.LzCategoryService;
import com.youlai.boot.modules.content.service.LzTagService;
import com.youlai.boot.system.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.modules.content.mapper.LzArticleMapper;
import com.youlai.boot.modules.content.service.LzArticleService;
import com.youlai.boot.modules.content.model.entity.LzArticle;
import com.youlai.boot.modules.content.model.form.LzArticleForm;
import com.youlai.boot.modules.content.model.query.LzArticleQuery;
import com.youlai.boot.modules.content.model.vo.LzArticleVO;
import com.youlai.boot.modules.content.converter.LzArticleConverter;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;

/**
 * 文章服务实现类
 *
 * @author lz0816
 * @since 2025-02-25 16:26
 */
@Service
@RequiredArgsConstructor
public class LzArticleServiceImpl extends ServiceImpl<LzArticleMapper, LzArticle> implements LzArticleService {

    private final LzArticleConverter lzArticleConverter;
    private final LzCategoryService lzCategoryService;
    private final LzArticleTagService lzArticleTagService;
    private final LzTagService lzTagService;
    private final UserService userService;

    private final StringRedisTemplate redisTemplate;
    private static final String ARTICLE_VIEW_COUNT_KEY = "article:viewCount";

    /**
     * 记录文章浏览量
     */
    public void increaseViewCount(Long articleId) {
        // 每次浏览 +1
        redisTemplate.opsForHash().increment(ARTICLE_VIEW_COUNT_KEY, String.valueOf(articleId), 1);
        // 设置过期时间，防止长期占用 Redis 空间
        redisTemplate.expire(ARTICLE_VIEW_COUNT_KEY, 1, TimeUnit.DAYS);
    }


    /**
     * 获取 Redis 中的浏览量
     */
    public Long getViewCount(Long articleId) {
        String count = (String) redisTemplate.opsForHash().get(ARTICLE_VIEW_COUNT_KEY, String.valueOf(articleId));
        return count != null ? Long.parseLong(count) : 0L;
    }

    /**
     * 获取文章分页列表
     *
     * @param queryParams 查询参数
     * @return {@link IPage<LzArticleVO>} 文章分页列表
     */
    @Override
    public IPage<LzArticleVO> getLzArticlePage(LzArticleQuery queryParams) {
        Page<LzArticleVO> pageVO = this.baseMapper.getLzArticlePage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams
        );

        // 获取分类名以及tags
        pageVO.getRecords().forEach(item -> {
            if (item.getCategoryId() != null) {
                LzCategory lzCategory = lzCategoryService.getById(item.getCategoryId());
                if (lzCategory != null) {
                    item.setCategoryName(lzCategory.getName());
                }
                List<Long> tagIds = lzArticleTagService.tagListByArticleId(item.getId());
                if (CollectionUtil.isNotEmpty(tagIds)) {
                    List<LzTag> lzTags = lzTagService.listByIds(tagIds);
                    item.setTags(lzTags.stream().map(LzTag::getName).collect(Collectors.toList()));
                }
                // 通过createBy获取创建人名称
                item.setCreatedName(userService.getById(item.getCreateBy()).getUsername());
                // 通过updateBy获取更新人名称
                item.setUpdatedName(userService.getById(item.getUpdateBy()).getUsername());

                // 获取文章浏览量
                item.setViewCount(getViewCount(item.getId()));
            }
        });
        return pageVO;
    }

    /**
     * 获取文章表单数据
     *
     * @param id 文章ID
     * @return
     */
    @Override
    public LzArticleForm getLzArticleFormData(Long id) {
        LzArticle entity = this.getById(id);
        LzArticleForm lzArticleForm = lzArticleConverter.toForm(entity);
        List<Long> tagIds = lzArticleTagService.tagListByArticleId(id);
        if (CollectionUtil.isNotEmpty(tagIds)) {
            List<LzTag> lzTags = lzTagService.listByIds(tagIds);
            lzArticleForm.setTagIds(lzTags.stream().map(LzTag::getId).collect(Collectors.toList()));
        }
        return lzArticleForm;
    }

    /**
     * 新增文章
     *
     * @param formData 文章表单对象
     * @return
     */
    @Override
    public boolean saveLzArticle(LzArticleForm formData) {
        // 1. 保存文章，获取生成的 articleId
        LzArticle entity = lzArticleConverter.toEntity(formData);
        entity.setCreateBy(SecurityUtils.getUserId());
        entity.setUpdateBy(SecurityUtils.getUserId());

        boolean saveArticleSuccess = this.save(entity);  // 保存文章并获取成功标志
        if (!saveArticleSuccess) {
            return false;  // 如果保存文章失败，直接返回
        }

        // 2. 获取保存后的文章 ID
        Long articleId = entity.getId();

        // 3. 处理文章标签页
        updateArticleTag(articleId, formData);

        return true;  // 返回成功
    }

    /**
     * 更新文章
     *
     * @param id       文章ID
     * @param formData 文章表单对象
     * @return
     */
    @Override
    public boolean updateLzArticle(Long id, LzArticleForm formData) {
        updateArticleTag(id, formData);
        LzArticle entity = lzArticleConverter.toEntity(formData);
        entity.setUpdateBy(SecurityUtils.getUserId());
        return this.updateById(entity);
    }

    /**
     * 删除文章
     *
     * @param ids 文章ID，多个以英文逗号(,)分割
     * @return
     */
    @Override
    public boolean deleteLzArticles(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的文章数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        return this.removeByIds(idList);
    }

    public void updateArticleTag(Long articleId, LzArticleForm formData) {
        // 3. 删除旧的文章标签
        lzArticleTagService.remove(
                new LambdaQueryWrapper<LzArticleTag>()
                        .eq(LzArticleTag::getArticleId, articleId)
        );

        // 4. 新增文章标签
        if (CollectionUtil.isNotEmpty(formData.getTagIds())) {
            List<LzArticleTag> articleTags = formData.getTagIds()
                    .stream()
                    .map(tagId -> new LzArticleTag(articleId, tagId))  // 使用获取的 articleId
                    .toList();
            lzArticleTagService.saveBatch(articleTags);  // 批量保存标签
        }
    }

    // 获取浏览量前5的文章列表
    @Override
    public List<LzArticleVO> getHotArticles() {
        // redisTemplate.opsForHash()获取浏览量前5的文章ID
        // 获取 Redis 中所有文章浏览量
        Map<Object, Object> top5ArticleIds = redisTemplate.opsForHash().entries(ARTICLE_VIEW_COUNT_KEY);
        List<Long> top5ArticleIdsList = top5ArticleIds.entrySet().stream()
                .map(entry -> new AbstractMap.SimpleEntry<>(
                        Long.valueOf(entry.getKey().toString()),
                        Long.valueOf(entry.getValue().toString())
                )) // 转换成 Long 类型
                .sorted((a, b) -> b.getValue().compareTo(a.getValue()))// 按浏览量降序排序
                .limit(5) // 取前 5 个
                .map(Map.Entry::getKey) // 获取文章 ID
                .collect(Collectors.toList());
        if (top5ArticleIdsList.isEmpty()) {
            return Collections.emptyList(); // 如果 Redis 中没有数据，返回空列表
        }
        // 根据文章 ID 查询数据库，获取文章详细信息
        List<LzArticle> hotArticles = this.listByIds(top5ArticleIdsList);

        // 将查询到的文章信息转换为 LzArticleVO 对象列表
        List<LzArticleVO> hotArticleVOs = hotArticles.stream()
                .map(article -> {
                    LzArticle lzArticle = this.getById(article.getId());
                    LzArticleVO lzArticleVO = new LzArticleVO();
                    BeanUtils.copyProperties(lzArticle, lzArticleVO);
                    return lzArticleVO;
                })
                .collect(Collectors.toList());
        // 根据浏览量对hotArticleVOs 进行从大到小的排序
        hotArticleVOs.sort((a, b) -> b.getViewCount().compareTo(a.getViewCount()));
        return hotArticleVOs;
    }


}
